/**
 * @file chat.c
 * @brief Sorgente che racchiude le funzioni per la gestione di una semplice chat.
 *
 * Viene definita la funzione principale che serve da gestore dell'avvio della comunicazione
 * e le sottofunzioni private richiamate per gestire le varie fasi della stessa
 * comunicazione.
 *
 * @date Mar 29, 2012
 * @author Francesco Corvino
 */
#include "cutility.h"
#include "../../RscNet/rscNet.h"
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

/**
 * @brief Attende un'input dai due file descriptor forniti.
 *
 * @param fd0 primo file descriptor.
 * @param fd1 secondo file descriptor.
 * @return restituisce il valore del file descriptor che si è sboccato o -1
 * se nessuno dei due è attivo.
 */
int _Chat_waitInput(int fd0, int fd1){
	struct timeval tv;
	tv.tv_sec = 1000; tv.tv_usec = 0;
	fd_set fdsetread;
	FD_ZERO(&fdsetread);
	FD_SET(fd0,&fdsetread);
	FD_SET(fd1, &fdsetread);
	int maxfd = (fd0>fd1)?(fd0):(fd1);
	select(maxfd+1,&fdsetread,NULL,NULL,&tv);
	if(FD_ISSET(fd0,&fdsetread)) return fd0;
	else if(FD_ISSET(fd1,&fdsetread)) return fd1;
	return -1;
}

/**
 * @brief Avvia la procedura di scambio dei messaggi con il client.
 *
 * @param sockFd specifica il socket descriptor con cui effettuare la comunicazione.
 * @param sessFd specifica il file descriptor con cui comunicare con la sessione dell'utente.
 * @param name stringa da utilizzare per identificare la comunicazione.
 * @param connInfo informazioni di rete per la connessione.
 */
void _ChatScambiaMessaggi(int sockFd,int sessFd,char *name, AddressInfo * connInfo){
	char msg[1000]; int sizebuff = 1000;
	do {
		memset(msg,0,sizebuff);
		int ret = _Chat_waitInput(sockFd,sessFd);
		if(ret==sockFd){
			UDP_recvMsg(sockFd,msg,sizebuff,connInfo);
			AppLib_writeToHostF("%s --> %s",name,msg);
		} else {
			AppLib_readFromHost(msg,sizebuff);
			UDP_sendMsgTo(sockFd, connInfo, msg);
		}
	} while (strncmp(msg,"end",3)!=0);
	AppLib_writeToHostF("Sessione di comunicazione %s ternimata!",name);
}

/**
 * @brief Prova ad iniviare un messaggio verso un'indirizzo.
 */
bool _ChatTryConnection(int sockFd,AddressInfo * connInfo, char* nameChat){
	// ricava il messaggio di inizializzazione della chat
	char initMsg[255];
	sprintf(initMsg,"start %s", nameChat);
	// avvia una comunicazione
	if(!UDP_sendMsgTo(sockFd,connInfo,initMsg)){
		// il messaggio non è stato inviato..
		AppLib_writeToHostF(
				"Chat con %s non riuscita, impossibile inviare messaggi.",
				nameChat);
		return false;
	}
	return true;
}

/**
 * @brief implementa la funzione execute dell'interfaccia comando per avviare una chat.
 */
void exStartChat(){
	char address[255], port[20], name[30];
	int ret = 0;
	// recupera le informazioni sull'indirizzo con cui comunicare
	ret = AppLib_getParam("address",address, 255);
	if(ret<2) strcpy(address,"localhost");
	ret = AppLib_getParam("port",port, 20);
	if(ret<1) strcpy(port, CHAT_DEFAULT_PORT);
	ret = AppLib_getParam("name",name,30);
	if(ret<1) strcpy(name,CHAT_DEFAULT_NAME);
	// richiede un socket UDP
	AddressInfo connInfo;
	int sockFd = UDP_getFdSocketFor(address,port, &connInfo);
	if(sockFd == -1) {
		AppLib_writeToHostF(
				"Chat con %s non riuscita, errore di connessione per %s:%s",
				name, address, port);
		return;
	}
	// prova a inizializzare la connessione scambiando dei messaggi
	if(!_ChatTryConnection(sockFd, &connInfo,name)) return;
	// ricava il filedescriptor di input con cui scambiare i messaggi.
	int sessionFd = Session_getFDRead(AppLib_getMySession());
	// avvia lo scambio messaggi
	_ChatScambiaMessaggi(sockFd,sessionFd,name,&connInfo);
	close(sockFd);
}
